using System;
using System.Diagnostics;
using System.Text;
using System.Data;
using Resources;
using System.Web.Services;
using System.Web.Services.Protocols;
using LtMbs.CrmSdkHelperClass;
using CrmServiceWebReference;
namespace LtMbs
{
    /// <summary>
    /// ///
    /// ///    Notes exceptions, exclusions, or any other funny's you need 
    /// ///    to know about Case
    /// ///
    /// Liquid Thought
    /// Created by:Rihan
    /// 
    /// </summary>
    [WebService(Namespace = "http://LtMbs/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Case : System.Web.Services.WebService
    {
        #region fields
        private email _email;
        static readonly int _searchResultsSystemIdentifierColumnId = 4;
        readonly CrmService service;
        #endregion fields
        /// <summary>
        /// Initializes a new instance of the <see cref="Case"/> class.
        /// </summary>
        public Case()
        { 
            service = Common.CrmAutorize(); 
        }
        /// <summary>
        /// Retreives the feedback from the KMS system.
        /// </summary>
        [WebMethod]
        public string RetreiveFeedback()
        {
            int NumberOfRecordsRetreivedFromKms;
            int NumberOfRecordsImported = 0;

            string lastRunDate = System.Configuration.ConfigurationManager.AppSettings["lastFeedbackRunDate"].ToString();

            KalDev.CustomerFeedbackResults feedbackResults = RetreiveFeedback(lastRunDate);
            NumberOfRecordsRetreivedFromKms = feedbackResults.Amount;

            if (NumberOfRecordsRetreivedFromKms < 1)
            {
                return feedbackResults.Message + " searched records from: " + lastRunDate;
                Common.LogErrorMessage(feedbackResults.Message);
            }
            else
            {
                foreach (KalDev.CustomerFeedback feedback in feedbackResults.CustomerFeedbacks)
                {
                    //If the sent to CRM dateTime is less than last feedback date it should not
                    //be imported
                    //Sent to CRM is populated we do not import it, as the spesifications by Roger on 16/11/2007

                    if (string.IsNullOrEmpty(feedback.CRMSentDate))
                    {
                        create(feedback);
                        NumberOfRecordsImported += 1;
                    }
                }
                try
                {
                    Common.updateConfigFile(System.DateTime.Now.ToString());
                    return System.DateTime.Now.ToString() +
                        " records imported:" + NumberOfRecordsImported + Environment.NewLine
                        + " records retreived from KMS:" + NumberOfRecordsRetreivedFromKms.ToString();
                }
                catch (System.Exception error)
                {
                    Common.LogErrorMessage(error);
                }
            }

        }
        /// <summary>
        /// Converts the CRM email into incident.
        /// </summary>
        /// <param name="CrmEmailId">The CRM email id.</param>
        /// <returns></returns>
        [WebMethod]
        public string ConvertCrmEmailIntoIncident(string CrmEmailId)
        {
            LoadEmail(new Guid(CrmEmailId));
            incident localCase = new incident();
            #region incidentmapping
            localCase.customerid = RetreiveCustomer();
            localCase.description = convertEmail(_email);
            localCase.title = string.Concat(Resources.Resource.ConvertedEmailSubjectPreFix, _email.subject);
            localCase.caseorigincode = CrmSdkHelperClass.CrmTypes.CreatePicklist(int.Parse(Resource.ConvertEmailOrginPickListId));
            #endregion incidentmapping
            Guid CreatedIncidentId;

            CreatedIncidentId = service.Create(localCase);
            attachActivityToIncident(CreatedIncidentId);
            detachEmailFromQueue(new Guid(CrmEmailId));
            //TODO: Changes on the 15th    
            //routeIncidentFromSupportQueueToUserWorkInProgressQue(CreatedIncidentId);

            return CreatedIncidentId.ToString(); ;
        }
        /// <summary>
        /// Launches the work flow.
        /// </summary>
        /// <param name="EntityId">The entity id.</param>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="workFlowId">The work flow id.</param>
        [WebMethod]
        public void LaunchWorkFlow(string EntityId, string entityType, string workFlowId)
        {
            ExecuteWFProcessRequest request = new ExecuteWFProcessRequest();
            request.ProcessId = new Guid(workFlowId);
            request.EntityMoniker = new Moniker();
            request.EntityMoniker.Name = entityType;
            request.EntityMoniker.Id = new Guid(EntityId);
            try
            {
                ExecuteWFProcessResponse response = (ExecuteWFProcessResponse)service.Execute(request);
            }
            catch (SoapException error)
            {
                Common.LogErrorMessage(error);
            }
        }
        /// <summary>
        /// Converts a email to a formated text string
        /// </summary>
        /// <param name="sourceEmail">The source _email, that will be used to create the case, based on its content</param>
        /// <returns>clear text string</returns>
        /// <remarks>
        /// This is according to spesification document Version 5 dated 29-08-2007
        /// </remarks>
        private string convertEmail(email sourceEmail)
        {
            StringBuilder emailInformation = new StringBuilder();

            emailInformation.AppendFormat("{0} {1}", Resource.EmailDescriptionPrefix, Common.removeHTMLTags(sourceEmail.description));
            emailInformation.AppendLine();
            emailInformation.AppendFormat("{0} {1}", Resource.EmailSubjectPrefix, Common.removeHTMLTags(sourceEmail.subject));
            emailInformation.AppendLine();
            emailInformation.AppendFormat("{0} {1}", Resource.EmailFromPrefix, sourceEmail.sender);
            emailInformation.AppendLine();

            foreach (activityparty person in sourceEmail.cc)
            {
                emailInformation.Append(RetreiveEmailAddress(person));
            }
            foreach (activityparty person in sourceEmail.bcc)
            {
                emailInformation.Append(RetreiveEmailAddress(person));
            }
            return emailInformation.ToString();
        }
        /// <summary>
        /// Retreives the customer details, from the email address that the email is from.
        /// If it finds it in CRM, or KMS it will continue to return the guid, but there might be a user
        /// that is unknown to both systems, this method creates that contact as well, and then returns the guid
        /// The contact is created with a first name of Auto Created Contact and last name of its email address.  This is done
        /// because at this time, their is not enough enformation to determine the users Firstname Lastname
        /// </summary>
        /// <returns>
        /// 	<list type="bullet">
        /// 		<item>There should only ever be one sender of a email, this code force's that assumption.</item>
        /// 	</list>
        /// </returns>
        private Customer RetreiveCustomer()
        {
            string emailAddress = _email.from[0].addressused;
            Guid customerID = new Guid();
            //Uses all ready built search to retreive information
            DataTable results = new CombinedSearch().Search(emailAddress);
            if (results.Rows.Count > 0)
            {
                string customerIdUnformated = results.Rows[0].ItemArray.GetValue(_searchResultsSystemIdentifierColumnId).ToString();
                switch (customerIdUnformated.Length)
                {
                    case 38:
                        customerID = new Guid(results.Rows[0].ItemArray.GetValue(_searchResultsSystemIdentifierColumnId).ToString());
                        break;
                    case 32:
                        customerID = Contact.CreateCrmContact(results.Rows[0].ItemArray.GetValue(_searchResultsSystemIdentifierColumnId).ToString());
                        break;
                }
            }
            else
            {
                customerID = new Guid(Contact.createUnknownContact(emailAddress, "Auto Created Contact", emailAddress));
            }
            return CrmSdkHelperClass.CrmTypes.CreateCustomer(EntityName.contact.ToString(), customerID);
        }
        /// <summary>
        /// Retreives the customer, if there is not a CRM email to work with. This is used when importing web cases
        /// </summary>
        /// <param name="emailAddress">The email address.</param>
        /// <returns>CrmCustomer</returns>
        private Customer RetreiveCustomer(string emailAddress, KalDev.CustomerFeedback sourceFeedbackEntry)
        {
            Guid customerID = new Guid();
            //Uses all ready built search to retreive information
            DataTable results = new CombinedSearch().Search(emailAddress);
            if (results.Rows.Count > 0)
            {
                string customerIdUnformated = results.Rows[0].ItemArray.GetValue(_searchResultsSystemIdentifierColumnId).ToString();
                switch (customerIdUnformated.Length)
                {
                    case 38:
                        customerID = new Guid(results.Rows[0].ItemArray.GetValue(_searchResultsSystemIdentifierColumnId).ToString());
                        break;
                    case 32:
                        customerID = Contact.CreateCrmContact(results.Rows[0].ItemArray.GetValue(_searchResultsSystemIdentifierColumnId).ToString());
                        break;
                }
            }
            else
            {
                if (sourceFeedbackEntry.ShopperId.Length > 1)
                {
                    customerID = Contact.CreateCrmContact(sourceFeedbackEntry.ShopperId);
                }
                else
                {
                    customerID = new Guid(Contact.createUnknownContact(emailAddress, sourceFeedbackEntry.FirstName, sourceFeedbackEntry.LastName));
                }

            }

            return CrmSdkHelperClass.CrmTypes.CreateCustomer(EntityName.contact.ToString(), customerID);

        }
        /// <summary>
        /// Retreives the email address from the activityparty
        /// </summary>
        /// <param name="person">Activity Party</param>
        /// <returns>string to be appended</returns>
        private string RetreiveEmailAddress(activityparty person)
        {
            StringBuilder emailAddress = new StringBuilder();
            emailAddress.AppendFormat("{0}", person.addressused);
            return emailAddress.ToString();
        }
        /// <summary>
        /// Loads the email, into memory
        /// </summary>
        /// <param name="emailId">The email id.</param>
        private void LoadEmail(Guid emailId)
        {
            TargetRetrieveEmail target = new TargetRetrieveEmail();
            target.EntityId = emailId;

            RetrieveRequest retrieve = new RetrieveRequest();
            retrieve.Target = target;
            retrieve.ColumnSet = new AllColumns();

            RetrieveResponse retreived = (RetrieveResponse)service.Execute(retrieve);
            _email = (email)retreived.BusinessEntity;
        }
        /// <summary>
        /// Creates the specified feedback entry as  crm incident.
        /// </summary>
        /// <param name="feedbackEntryToReCreate">The feedback entry to re create.</param>
        private void create(KalDev.CustomerFeedback feedbackEntryToReCreate)
        {

            incident feedbackIncident = new incident();

            // feedbackIncident.customerid = localCustomer;
            feedbackIncident.title = feedbackEntryToReCreate.CustomerFeedbackID + feedbackEntryToReCreate.FeedbackCategoryList;
            feedbackIncident.new_kalahariwebsitereference = feedbackEntryToReCreate.CustomerFeedbackID;
            feedbackIncident.new_ordernumber = feedbackEntryToReCreate.ShortOrderID;
            feedbackIncident.customerid = RetreiveCustomer(feedbackEntryToReCreate.Email, feedbackEntryToReCreate);
            System.Text.StringBuilder description = new StringBuilder();
            description.AppendLine(feedbackEntryToReCreate.FeedbackMessage);
            feedbackIncident.description = description.ToString();
            feedbackIncident.new_kalahariwebsitereference = feedbackEntryToReCreate.CustomerFeedbackID;
            feedbackIncident.caseorigincode = CrmTypes.CreatePicklist(int.Parse(Resource.ImportWebCaseOrginPickListId));
            try
            {
                CrmService service = Common.CrmAutorize();
                Guid IncidentId = service.Create(feedbackIncident);
                routeIncidentFromSupportQueueToUserWorkInProgressQue(IncidentId);

            }
            catch (SoapException spException)
            {
                Common.LogErrorMessage(spException);
            }
        }
        /// <summary>
        /// Retreives the customer.
        /// </summary>
        /// <param name="sourceFeedbackEntry">The source feedback entry.</param>
        /// <returns></returns>
        private Customer retreiveCustomer(KalDev.CustomerFeedback sourceFeedbackEntry)
        {
            Guid customerId = new Guid();
            DataTable searchResults = new CombinedSearch().Search(sourceFeedbackEntry.Email);
            if (searchResults.Rows.Count > 0)
            {
                customerId = new Guid(searchResults.Rows[0].ItemArray.GetValue(_searchResultsSystemIdentifierColumnId).ToString());
            }
            else
            {
                if (sourceFeedbackEntry.ShopperId.Length > 1)
                {
                    customerId = Contact.CreateCrmContact(sourceFeedbackEntry.ShopperId);
                }
            }
            return CrmTypes.CreateCustomer(EntityName.contact.ToString(), customerId);
        }
        /// <summary>
        /// Routes the incident.
        /// </summary>
        /// <param name="IncidentToRoute">The incident to route.</param>
        private void routeIncidentFromSupportQueueToUserWorkInProgressQue(Guid IncidentToRoute)
        {
            TargetQueuedIncident incident = new TargetQueuedIncident();
            incident.EntityId = IncidentToRoute;

            RouteRequest request = new RouteRequest();
            request.Target = incident;
            request.RouteType = RouteType.Queue;
            request.EndpointId = Common.wipQueue().queueid.Value;
            request.SourceQueueId = new Guid(System.Configuration.ConfigurationManager.AppSettings[Resource.AppSettingsSupportQueueId].ToString());
            
            RouteResponse response = (RouteResponse)service.Execute(request);
        }
        /// <summary>
        /// Attaches the activity to incident.
        /// </summary>
        /// <param name="IncidentId">The incident id.</param>
        private void attachActivityToIncident(Guid IncidentId)
        {
            email email = _email;
            email.regardingobjectid = CrmTypes.CreateLookup(EntityName.incident.ToString(), IncidentId);
            TargetUpdateEmail target = new TargetUpdateEmail();
            target.Email = email;

            UpdateRequest update = new UpdateRequest();
            update.Target = target;
            try
            {
                service.Execute(update);
            }
            catch (SoapException soapError)
            {
                Common.LogErrorMessage(soapError);
            }
        }
        /// <summary>
        /// Routes the incident to users work in progress queue from the support queue
        /// </summary>
        /// <param name="IncidentId">The incident id.</param>
        private void acceptIncident(Guid IncidentId)
        {
            TargetQueuedIncident target = new TargetQueuedIncident();
            target.EntityId = IncidentId;
            RouteRequest route = new RouteRequest();
            route.Target = target;
            route.EndpointId = service.CallerIdValue.CallerGuid;
            route.RouteType = RouteType.User;

            RouteResponse response = (RouteResponse)service.Execute(route);

        }
        /// <summary>
        /// Detaches the email from queue.
        /// </summary>
        /// <param name="EmailId">The email id.</param>
        private void detachEmailFromQueue(Guid EmailId)
        {
            DetachFromQueueEmailRequest request = new DetachFromQueueEmailRequest();
            request.EmailId = EmailId;
            request.QueueId = new Guid(System.Configuration.ConfigurationManager.AppSettings[Resource.AppSettingsSupportQueueId].ToString());

            DetachFromQueueEmailResponse response = (DetachFromQueueEmailResponse)service.Execute(request);

        }
        /// <summary>
        /// Retreives the feedback.
        /// </summary>
        /// <param name="lastDateRun">The last date run.</param>
        /// <returns></returns>
        private KalDev.CustomerFeedbackResults RetreiveFeedback(string lastDateRun)
        {
            KalDev.CRMService service = Common.KmsAuthorize();
            KalDev.CustomerFeedbackResults customerFeedbackResults = new KalDev.CustomerFeedbackResults();
            try
            {
                customerFeedbackResults = service.SearchCustomerFeedback(lastDateRun);
            }
            catch (SoapException sp)
            {
                Common.LogErrorMessage(sp);
            }
                return customerFeedbackResults;
        }
        /// <summary>
        /// Emails the out.
        /// </summary>
        /// <param name="emailId">The email id.</param>
        private void EmailOut(Guid emailId)
        {
            TargetQueuedEmail target = new TargetQueuedEmail();
            target.EntityId = emailId;
            RouteRequest request = new RouteRequest();
            request.Target = target;
            request.RouteType = RouteType.Auto;
            request.SourceQueueId = new Guid(System.Configuration.ConfigurationManager.AppSettings[Resource.AppSettingsSupportQueueId].ToString());
            try
            {
                service.Execute(request);
            }
            catch (SoapException soapException)
            {
                Common.LogErrorMessage(soapException);
            }
        }
        
    }
}